#include "stdafx.h"
#include "Cube.h"

namespace WindGE
{
	Cube::Cube(const Cube& cube)
	{
		Pos0 = cube.Pos0;
		Pos1 = cube.Pos1;
		Center = cube.Center;
		Radius = cube.Radius;

		update_normal();
	}

	Cube::Cube(CubePtr cube)
	{
		Pos0 = cube->Pos0;
		Pos1 = cube->Pos1;
		Center = cube->Center;
		Radius = cube->Radius;

		update_normal();
	}

	Cube::Cube(const XMFLOAT3& center, float width, float height, float depth)
		: Center(center)
		, Radius(width / 2.0f, height / 2.0f, depth / 2.0f)
		, Pos0(XMFLOAT3(Center.x - Radius.x, Center.y - Radius.y, Center.z - Radius.z))
		, Pos1(XMFLOAT3(Center.x + Radius.x, Center.y + Radius.y, Center.z + Radius.z))
	{
		update_normal();
	}

	Cube::Cube(const XMFLOAT3& p0, const XMFLOAT3& p1)
		: Pos0(p0)
		, Pos1(p1)
		, Center((p0.x + p1.x) / 2.0f, (p0.y + p1.y) / 2.0f, (p0.z + p1.z) / 2.0f)
		, Radius((p1.x - p0.x) / 2.0f, (p1.y - p0.y) / 2.0f, (p1.z - p0.z) / 2.0f)
	{
		update_normal();
	}

	Cube::Cube(const XMFLOAT3& center, float length)
		: Center(center)
		, Radius(length / 2.0f, length / 2.0f, length / 2.0f)
		, Pos0(XMFLOAT3(Center.x - Radius.x, Center.y - Radius.y, Center.z - Radius.z))
		, Pos1(XMFLOAT3(Center.x + Radius.x, Center.y + Radius.y, Center.z + Radius.z))
	{
		update_normal();
	}

	void Cube::reset()
	{
		Center = XMFLOAT3(0.0f, 0.0f, 0.0f);
		Radius = XMFLOAT3(0.0f, 0.0f, 0.0f);
		Pos0 = XMFLOAT3(0.0f, 0.0f, 0.0f);
		Pos1 = XMFLOAT3(0.0f, 0.0f, 0.0f);
	}

	void Cube::set(const XMFLOAT3& p0, const XMFLOAT3& p1)
	{
		Pos0 = p0;
		Pos1 = p1;
		Center = XMFLOAT3((p0.x + p1.x) / 2.0f, (p0.y + p1.y) / 2.0f, (p0.z + p1.z) / 2.0f);
		Radius = XMFLOAT3((p1.x - p0.x) / 2.0f, (p1.y - p0.y) / 2.0f, (p1.z - p0.z) / 2.0f);

		update_normal();
	}

	void Cube::set(float rx, float ry, float rz, const XMFLOAT3& center)
	{
		Center = center;
		Radius.x = rx; Radius.y = ry; Radius.z = rz;

		Pos0 = XMFLOAT3(Center.x - Radius.x, Center.y - Radius.y, Center.z - Radius.z);
		Pos1 = XMFLOAT3(Center.x + Radius.x, Center.y + Radius.y, Center.z + Radius.z);

		update_normal();
	}

	void Cube::set(const Cube& cube)
	{
		Pos0 = cube.Pos0;
		Pos1 = cube.Pos1;
		Center = cube.Center;
		Radius = cube.Radius;

		update_normal();
	}

	void Cube::set(CubePtr cube)
	{
		Pos0 = cube->Pos0;
		Pos1 = cube->Pos1;
		Center = cube->Center;
		Radius = cube->Radius;

		update_normal();
	}

	void Cube::set(float radius, const XMFLOAT3& center)
	{
		Radius = XMFLOAT3(radius, radius, radius);
		Center = center;

		Pos0 = XMFLOAT3(Center.x - Radius.x, Center.y - Radius.y, Center.z - Radius.z);
		Pos1 = XMFLOAT3(Center.x + Radius.x, Center.y + Radius.y, Center.z + Radius.z);

		update_normal();
	}

	XMFLOAT4X4 Cube::world_matrix() const
	{
		XMFLOAT4X4 world;
		XMFLOAT4 R(0.0f, 0.0f, 0.0f, 0.0f);
		TransformToMatrix(world, Center, R, Radius);
		return world;
	}

	void Cube::transform(const XMMATRIX& trans)
	{
		XMVECTOR vecPos0 = XMLoadFloat3(&Pos0);
		vecPos0 = XMVector3Transform(vecPos0, trans);
		XMStoreFloat3(&Pos0, vecPos0);

		XMVECTOR vecPos1 = XMLoadFloat3(&Pos1);
		vecPos1 = XMVector3Transform(vecPos1, trans);
		XMStoreFloat3(&Pos1, vecPos1);

		Center = XMFLOAT3((Pos0.x + Pos1.x) / 2.0f, (Pos0.y + Pos1.y) / 2.0f, (Pos0.z + Pos1.z) / 2.0f);
		Radius = XMFLOAT3((Pos1.x - Pos0.x) / 2.0f, (Pos1.y - Pos0.y) / 2.0f, (Pos1.z - Pos0.z) / 2.0f);

		update_normal();
	}

	const XMFLOAT3& Cube::get_transform_center(const XMMATRIX& trans) const
	{
		static XMFLOAT3 C = Center;

		XMVECTOR vecPos0 = XMLoadFloat3(&Pos0);
		vecPos0 = XMVector3Transform(vecPos0, trans);
		XMVECTOR vecPos1 = XMLoadFloat3(&Pos1);
		vecPos1 = XMVector3Transform(vecPos1, trans);
		vecPos0 = (vecPos0 + vecPos1) / 2.0f;
		XMStoreFloat3(&C, vecPos0);

		return C;
	}

	const XMFLOAT3& Cube::get_transform_size(const XMMATRIX& trans) const
	{
		static XMFLOAT3 R;
		R = Radius;

		R.x = Radius.x * trans._11;
		R.y = Radius.y * trans._22;
		R.z = Radius.z * trans._33;

		return R;
	}

	void Cube::get_transform_center_size(const XMMATRIX& trans, XMFLOAT3& center, XMFLOAT3& radius) const
	{
		XMVECTOR vecPos0 = XMLoadFloat3(&Pos0);
		vecPos0 = XMVector3Transform(vecPos0, trans);
		XMVECTOR vecPos1 = XMLoadFloat3(&Pos1);
		vecPos1 = XMVector3Transform(vecPos1, trans);

		XMVECTOR vec = (vecPos0 + vecPos1) / 2.0f;
		XMStoreFloat3(&center, vec);

		radius.x = Radius.x * trans._11;
		radius.y = Radius.y * trans._22;
		radius.z = Radius.z * trans._33;
	}

	void Cube::update_normal()
	{
		Normal0.x = Pos1.x - Center.x;
		Normal0.y = Pos1.y - Center.y;
		Normal0.z = Pos1.z - Center.z;

		Normal1.x = Pos1.x - Center.x;
		Normal1.y = Pos0.y - Center.y;
		Normal1.z = Pos1.z - Center.z;

		Normal2.x = Pos0.x - Center.x;
		Normal2.y = Pos0.y - Center.y;
		Normal2.z = Pos1.z - Center.z;

		Normal3.x = Pos0.x - Center.x;
		Normal3.y = Pos1.y - Center.y;
		Normal3.z = Pos1.z - Center.z;
	}
}